package cl.blueprintsit.utils.files;

import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.log4j.Logger;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.MalformedURLException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static java.util.Collections.emptyList;
import static org.apache.commons.io.IOUtils.toByteArray;

public class FileUtils {

    private static Logger logger = Logger.getLogger(FileUtils.class);

    /**
     * This method is responsible for checking whether a specific file is reachable.
     *
     * @param filePath The path of the file to be checked.
     * @return <code>true</code> if the file is reachable and <code>false</code> otherwise.
     */
    public static boolean connect(String filePath) {
        File file = new File(filePath);
        return file.exists();
    }

    /**
     * This method is responsible for returning an array containing all the files contained in the given Directory.
     *
     * @param theFolder The directory from which the files contained are listed.
     * @return A list with a reference to all the files contained the <code>theFolder</code>.
     * @throws FileNotFoundException Thrown if <code>theFolder</code> does not exist.
     */
    public static List<File> getFilesFromFolder(File theFolder) throws FileNotFoundException {

        /* If the file does not exists, an exception is thrown */
        if (!theFolder.exists()) {
            throw new FileNotFoundException(theFolder.getAbsolutePath());
        }

        /* If the folder is a file, an empty list is returned */
        if (!theFolder.isDirectory()) {
            return emptyList();
        }

        File[] files = theFolder.listFiles();
        return Arrays.asList(files);
    }

    /**
     * @return
     * @throws FileNotFoundException
     */
    public static List<SmbFile> getFilesFromSambaFolder(String host, String username, String password, String path) throws SmbException, MalformedURLException {
        NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(null, username, password);
        SmbFile dir = new SmbFile("smb://" + host + "/" + path, auth);

        SmbFile[] smbFiles = dir.listFiles();
        return Arrays.asList(smbFiles);
    }

    public static List<File> getDirectoryFromFolder(File directory) throws FileNotFoundException, NotADirectoryException {

        if (directory == null) return Collections.emptyList();
        if (!directory.exists()) throw new FileNotFoundException(directory.getPath());
        if (!directory.isDirectory()) throw new NotADirectoryException();

        FileFilter directoryFilter = new DirectoryFilter();
        return Arrays.asList(directory.listFiles(directoryFilter));
    }

    /**
     * This method is responsible for reading the bytes from a file and returning them in a byte array.
     *
     * @param file The file from which the contents are read.
     * @return The file's content in an byte array.
     * @throws IOError Thrown if the file does not exist or if there are problems while reading it..
     */
    public static byte[] getContents(File file) throws IOException {

        /* If there is no such file, the exception is thrown */
        if (!file.exists())
            throw new FileNotFoundException("The file does not exist.");

        return toByteArray(new FileInputStream(file));
    }

    public static File createFile(HttpServletRequest req) throws FileUploadException {
        int maxMemSize = 10000 * 1024;
        int maxFileSize = 10000 * 1024;

        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setSizeThreshold(maxMemSize);
        factory.setRepository(new File("\\temp"));

        /** A handler for the file */
        ServletFileUpload upload = new ServletFileUpload(factory);
        upload.setSizeMax(maxFileSize);


        // Parse the request to get file items.
        List<FileItem> fileItems = upload.parseRequest(req);

        /* Simple validation */
        if (fileItems.size() == 0) {
            throw new FileUploadException("No file was uploaded.");
        } else if (fileItems.size() > 1) {
            throw new FileUploadException("More than one file was uploaded at once. This is an impossible error because the form has only one file field ");
        }

        /* The content file is retrieved */
        FileItem fileItem = fileItems.get(0);
        File uploadedFile = new File(fileItem.getName());
        try {
            fileItem.write(uploadedFile);
        } catch (Exception e) {
            logger.error("Error when writing the uploaded file.", e);
        }

        return uploadedFile;
    }
}

class DirectoryFilter implements FileFilter {
    @Override
    public boolean accept(File f) {
        return f.isDirectory();
    }
}
